package com.iwhalecloud.citybrain.flow.platform.manager.application.service.impl.task;

import com.alibaba.fastjson.JSONObject;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.BeanCopierUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.StringUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.eventconfig.EventExceptionDomain;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.monitor.FlowTaskTraceVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowEventExceptionRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowTaskTraceRepository;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Objects;

/**
 　　* @description: 流程组件同步待办组件待办异常处理
 　　* @author huhf
 　　* @date 2022/10/18
 　　*/
@Component
@Slf4j
public class EventExceptionHandler {

    @Autowired
    private FlowEventExceptionRepository flowEventExceptionRepository;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private FlowTaskTraceRepository flowTaskTraceRepository;

    @Autowired
    private RepositoryService repositoryService;



    public<T> void catchException(T data, String source, String exceptionMessage, List<String> taskIds, String processInstanceId ){
        //当更新内容为空时，不需要插入到异常信息表中
        if(Objects.isNull(data)){
            return;
        }
        //添加try catch 语句 的原因是：避免出现异常信息阻碍流程往下流转
        try {
            EventExceptionDomain temp = new EventExceptionDomain();
            temp.setExceptionMsg(exceptionMessage);
            temp.setRequestBody(JSONObject.toJSONString(data));
            temp.setCallMethod("异步");
            temp.setCallbackType("url");
            switch (source) {
                case "updateHandler":
                    temp.setName("待办更新处理人");
                    temp.setEventType("待办更新");
                    temp.setCallbackContent("http://common.cc.intra/tasks-manager-app/tasks/updateTasks");
                    break;
                case "updateEmergency":
                    temp.setName("待办更新紧急程度");
                    temp.setEventType("待办更新");
                    temp.setCallbackContent("http://common.cc.intra/tasks-manager-app/tasks/updateTasks");
                    break;
                case "updateStatus":
                    temp.setName("待办更新状态");
                    temp.setEventType("待办更新");
                    temp.setCallbackContent("http://common.cc.intra/tasks-manager-app/tasks/updateStatus");
                    break;
                case "delete":
                    temp.setName("待办删除");
                    temp.setEventType("待办删除");
                    temp.setCallbackContent("http://common.cc.intra/tasks-manager-app/tasks/delete");
                    break;
                default:
                    break;
            }
            insertException(taskIds, processInstanceId, temp);
        }
        catch(Exception e){
            log.info("插入异常信息时出现异常,processInstance:{}",processInstanceId);
        }

    }

    //更新待办异常信息
    public void insertException(List<String> taskIds,String processInstanceId,EventExceptionDomain temp){
        EventExceptionDomain eventExceptionDomain = new EventExceptionDomain();
        BeanCopierUtils.copyProperties(temp, eventExceptionDomain);
        try {
            //如果给的有任务id
            if(CollectionUtils.isNotEmpty(taskIds)){
                //异常信息关联流程信息 如果taskIds中有多个id 只关联第一个
                // 根据taskId获取任务轨迹记录
                FlowTaskTraceVo flowTaskTraceVo = flowTaskTraceRepository.getTaskTraceByTaskId(taskIds.get(0));
                if (Objects.nonNull(flowTaskTraceVo)) {
                    eventExceptionDomain.setModelKey(flowTaskTraceVo.getModelKey());
                    eventExceptionDomain.setModelName(flowTaskTraceVo.getModelName());
                    eventExceptionDomain.setProcessInstanceId(flowTaskTraceVo.getProcessInstanceId());
                    eventExceptionDomain.setNodeCode(flowTaskTraceVo.getActivityId());
                }
                // 根据流程实例ID获取流程实例
                ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(flowTaskTraceVo.getProcessInstanceId()).singleResult();
                //流程实例id
                ProcessDefinition processDefinition = repositoryService.getProcessDefinition(processInstance.getProcessDefinitionId());

                if(Objects.nonNull(processDefinition)){
                    eventExceptionDomain.setDeploymentId(processDefinition.getDeploymentId());
                    eventExceptionDomain.setModelId(getModelIdFromProcessDefinition(processDefinition.getId()));
                }
            }
            //如果给的有流程实例id
            if(StringUtils.isNotBlank(processInstanceId)){
                eventExceptionDomain.setProcessInstanceId(processInstanceId);
                // 根据流程实例ID获取流程实例
                ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
                //流程实例id
                ProcessDefinition processDefinition = repositoryService.getProcessDefinition(processInstance.getProcessDefinitionId());
                if (Objects.nonNull(processDefinition)) {
                    eventExceptionDomain.setModelKey(processDefinition.getKey());
                    eventExceptionDomain.setModelName(processDefinition.getName());
                    eventExceptionDomain.setNodeCode(getNodeCodeByProInstanceId(processInstanceId));
                    eventExceptionDomain.setDeploymentId(processDefinition.getDeploymentId());
                    eventExceptionDomain.setModelId(getModelIdFromProcessDefinition(processDefinition.getId()));
                }
            }
        }
        catch(Exception ex){
            log.info("流程组件同步待办组件任务处理人异常信息 关联流程实例失败 只存储异常信息,流程实例id：{}",taskIds);
        }
        try {
            flowEventExceptionRepository.insertEventException(eventExceptionDomain);
        }catch(Exception e){
            log.error("记录批量更新待办任务计划完成时间异常时出现异常，异常信息为：{}",e.getMessage(),e);
        }
    }

    public String getNodeCodeByProInstanceId(String processInstanceId){
        if(StringUtils.isBlank(processInstanceId)){
            return null;
        }
        String nodeCode="";
        try{
            List<FlowTaskTraceVo> flowTaskTraceVoList=flowTaskTraceRepository.getFlowTaskTracesByProInsIdAndLinkStatus(processInstanceId,"TODO");
            if(CollectionUtils.isNotEmpty(flowTaskTraceVoList)){
                FlowTaskTraceVo flowTaskTraceVo=flowTaskTraceVoList.get(0);
                nodeCode=flowTaskTraceVo.getActivityId();
            }
        }catch(Exception e){
            log.info("根据processInstanceId查询taskId失败，processInstanceId:{}",processInstanceId);
        }
        return nodeCode;
    }


    //更新待办任务计划完成时间异常记录
    public<T> void catchException(T data, EventExceptionDomain temp){
        //当更新内容为空时，不需要插入到异常信息表中
        if(Objects.isNull(data)){
            return;
        }
        try {
            String requestParam = JSONObject.toJSONString(data);
            EventExceptionDomain eventExceptionDomain = new EventExceptionDomain();
            if(Objects.nonNull(temp)){
                BeanCopierUtils.copyProperties(temp,eventExceptionDomain);
            }
            eventExceptionDomain.setRequestBody(requestParam);
            eventExceptionDomain.setName("待办修改完成时间");
            eventExceptionDomain.setEventType("待办修改");
            eventExceptionDomain.setCallMethod("异步");
            eventExceptionDomain.setCallbackType("url");
            flowEventExceptionRepository.insertEventException(eventExceptionDomain);
        }catch(Exception e){
            log.error("记录批量更新待办任务计划完成时间异常时出现异常，异常信息为：{}",e.getMessage(),e);
        }
    }


    //如果插入待办失败，将信息存储到异常表中
    public void catchException(EventExceptionDomain temp, TaskEntity taskEntity){
        try {
            EventExceptionDomain eventExceptionDomain = new EventExceptionDomain();
            BeanCopierUtils.copyProperties(temp,eventExceptionDomain);
            eventExceptionDomain.setCallMethod("异步");
            eventExceptionDomain.setCallbackType("url");
            if (Objects.nonNull(taskEntity)) {
                String processInstanceId = taskEntity.getProcessInstanceId();
                eventExceptionDomain.setProcessInstanceId(processInstanceId);
                eventExceptionDomain.setNodeCode(taskEntity.getTaskDefinitionKey());  //获取节点编码
                ProcessDefinition processDefinition = repositoryService.getProcessDefinition(taskEntity.getProcessDefinitionId());
                //获取部署id
                if (Objects.nonNull(processDefinition)) {
                    eventExceptionDomain.setDeploymentId(processDefinition.getDeploymentId());
                    eventExceptionDomain.setModelId(getModelIdFromProcessDefinition(processDefinition.getId()));
                    eventExceptionDomain.setModelKey(processDefinition.getKey());
                    eventExceptionDomain.setModelName(processDefinition.getName());
                }
                // 根据taskId获取任务轨迹记录，填充modelName & modelKey
//                FlowTaskTraceVo flowTaskTraceVo = flowTaskTraceRepository.getTaskTraceByTaskId(taskEntity.getId());
//                if (Objects.nonNull(flowTaskTraceVo)) {
//                    eventExceptionDomain.setModelName(flowTaskTraceVo.getModelName());
//                    eventExceptionDomain.setModelKey(flowTaskTraceVo.getModelKey());
//                    //eventExceptionDomain.setNodeCode(flowTaskTraceVo.getActivityId()); //获取节点编码
//                }
            }
            flowEventExceptionRepository.insertEventException(eventExceptionDomain);
        }catch(Exception e){
            log.error("待办异常新增时出现异常，异常信息为：{}",e.getMessage(),e);
        }

    }

    public void catchException(EventExceptionDomain temp, ExecutionEntity executionEntity){
        try {
            EventExceptionDomain eventExceptionDomain = new EventExceptionDomain();
            BeanCopierUtils.copyProperties(temp, eventExceptionDomain);
            eventExceptionDomain.setCallMethod("异步");
            eventExceptionDomain.setCallbackType("url");
            if (Objects.nonNull(executionEntity)) {
                String processInstanceId = executionEntity.getProcessInstanceId();
                eventExceptionDomain.setNodeCode(executionEntity.getCurrentActivityId());
                eventExceptionDomain.setProcessInstanceId(processInstanceId);
                eventExceptionDomain.setDeploymentId(executionEntity.getDeploymentId());
                ProcessDefinition processDefinition = repositoryService.getProcessDefinition(executionEntity.getProcessDefinitionId());
                if (Objects.nonNull(processDefinition)) {
                    eventExceptionDomain.setModelId(getModelIdFromProcessDefinition(processDefinition.getId()));
                    eventExceptionDomain.setModelKey(processDefinition.getKey());
                    eventExceptionDomain.setModelName(processDefinition.getName());
                }
            }
            flowEventExceptionRepository.insertEventException(eventExceptionDomain);
        }
        catch(Exception e){
            log.error("待办异常新增时（修改）出现异常，异常信息为：{}",e.getMessage(),e);
        }
    }

    public String getModelIdFromProcessDefinition(String processDefinition){
        if(StringUtils.isBlank(processDefinition)){
            return processDefinition;
        }
        if(processDefinition.contains(":")){
            String[] temp=processDefinition.split(":");
            if(temp.length==3){
                return temp[2];
            }
        }
        return processDefinition;
    }


}
